package com.kaisu.blog.infrastructure.user.repository.impl;

import cn.hutool.core.util.StrUtil;
import com.kaisu.blog.common.exceptions.InternalException;
import com.kaisu.blog.domain.user.User;
import com.kaisu.blog.domain.user.repository.UserRepository;
import com.kaisu.blog.infrastructure.user.UserPO;
import com.kaisu.blog.infrastructure.user.convert.UserConvert;
import com.kaisu.blog.infrastructure.user.dao.UserPODAO;
import jakarta.persistence.criteria.Predicate;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author kaisu
 */
@Repository
@RequiredArgsConstructor
public class UserRepositoryImpl implements UserRepository {
    private final UserConvert userConvert;
    private final UserPODAO userPODAO;

    @Override
    public void save(User user) {
        userPODAO.save(userConvert.toPO(user));
    }

    @Override
    public User findById(String id) {
        return userConvert.toDomain(this.findPOById(id));
    }

    @Override
    public boolean checkUnique(User user) {
        return userPODAO.findByUsernameOrEmailOrPhone(user.getUsername(), user.getEmail(), user.getPhone()).isPresent();
    }

    @Override
    public User findByAccount(String account) {
        return userPODAO.findByUsernameOrEmailOrPhone(account, account, account).map(userConvert::toDomain).orElseThrow(() -> new InternalException("用户不存在！"));
    }

    @Override
    public Collection<User> findAllByAccount(Collection<String> usernames) {
        return userPODAO.findAllByPhoneIn(usernames).stream().map(userConvert::toDomain).toList();
    }

    private UserPO findPOById(String id) {
        return userPODAO.findById(id)
                .orElseThrow(() -> new InternalException("用户不存在！"));
    }

    @Override
    public Set<User> findByIds(Set<String> ids) {
        return userPODAO.findAllById(ids).stream().map(userConvert::toDomain).collect(Collectors.toSet());
    }

    @Override
    public Page<User> page(String condition, Pageable pageable) {
        Page<UserPO> page = userPODAO.findAll((Specification<UserPO>) (root, query, criteriaBuilder) -> {
            // 构建模糊查询条件
            if (StrUtil.isNotEmpty(condition)) {
                List<Predicate> predicates = new ArrayList<>();
                Predicate name = criteriaBuilder.like(root.get("username"), "%" + condition + "%");
                predicates.add(name);
                return criteriaBuilder.or(predicates.toArray(new Predicate[0]));
            } else {
                return null;
            }
        }, pageable);
        return page.map(userConvert::toDomain);
    }

    @Override
    public void saveBatch(List<User> userList) {
        userPODAO.saveAll(userList.stream().map(userConvert::toPO).toList());
    }
}
